﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufBase.h"
#include "GnufArrangementArea.h"
#include "GnufBaseUtils.h"
#include "GnufImpl.h"

namespace {
    class ArrangementAreaOperator;
}
class QWidget;
namespace gnuf {
    
    class Pallet;
    class Info;
    class ArrangementArea;
    class DockingArrangementArea;
    /*
        +-------------------------------------------------------------------+
        | Header                                                            |
        +-------------------------------------------------------------------+
        |                                                                   |
        |                                                                   |
        |                           C o n t e n t                           |
        |                                                                   |
        |                                                                   |
        +-------------------------------------------------------------------+
        | Footer                                          [ OK ] [ Cancel ] |
        +-------------------------------------------------------------------+
    */

    class GNUF_BASE_EXPORT IPalletEventHandler : public gcmp::WeakReferenceable
    {
    public:
        virtual void onHeaderTabChanged(Pallet *) {}
        virtual void onHeaderButtonClicked(Pallet *) {}
        virtual bool onFooterButtonClicked(Pallet *) { return true; }
        virtual bool onFooterCheckStateChanged(Pallet*) { return true; }
        virtual void onRefreshStyle() {};
        enum class EKey {
            eEscape
        };
        enum class EMouse {
            eEnter,
            eLeave
        };
        virtual bool onKeyEvent(Pallet *, IPalletEventHandler::EKey) { return false; }
        virtual void onMouseEvent(Pallet *, IPalletEventHandler::EMouse) {}
        virtual void onContentChanged(Pallet *) {}
        virtual void onScaleFactorChanged(const ScaleFactor &) {}
        virtual bool onIsMasked() const { return false; }
        virtual bool onDoClose() { return true; }
    };

    class GNUF_BASE_EXPORT Header : public gcmp::WeakReferenceable
    {
        CANNOT_COPY_OR_ASSIGN(Header);
    public:
        //
        //OverAll
        struct { bool left, top, right, bottom; } wantBorder;
        struct { int left, top, right, bottom, spacing; } padding;

        bool wantBackground;
        bool wantToAlignLeft;
        //
        // Icon.
        gcmp::OwnerPtr< Info > icon;
        struct { int left, top, right, bottom; } iconMargin;
        //
        // Caption.
        std::wstring caption;
        struct { int left, top, right, bottom; } captionMargin;

        //
        // Tabs.
        std::list< gcmp::OwnerPtr< Info > > tabs;
        int currentTab;
        bool showOnlyTabIcon;
        //
        // Methods.
        Header();
        void addTab(gcmp::OwnerPtr< Info > &);
        virtual bool empty() const;

        const Color& backgroundColor() const;
        const Color& captionColor() const;

        void setBackgroundColorCode(ColorCode code) { backgroundCode = code; }
        void setCaptionColorCode(ColorCode code) { captionCode = code; }

    private:
        ColorCode backgroundCode = ColorCode::Label02;
        ColorCode captionCode;
    };
    
    class GNUF_BASE_EXPORT PalletHeader : public Header
    {
        CANNOT_COPY_OR_ASSIGN(PalletHeader);
    public:
        bool canDragAndMove;
        //
        // Buttons.
        bool wantHoverButton = true;
        std::list< gcmp::OwnerPtr< Info > > buttons;
        int currentButton;
        struct { std::uint8_t r, g, b, a; } buttonHoverColor;
        struct { int left, top, right, bottom; } buttonMargin;
        //
        // Methods.
        PalletHeader();
        void addButton(gcmp::OwnerPtr< Info > &);
        virtual bool empty() const override;
    };
    
    class GNUF_BASE_EXPORT PalletFooter
    {
    public:
        //
        //OverAll
        struct { int left, top, right, bottom, spacing; } padding{ 0, 0, 0, 0 };

        //
        //Buttons
        struct { int left, top, right, bottom; } buttonMargin{0, 0, 0, 0};
        std::list< std::wstring > buttons;
        std::set<std::wstring > disabledButtons;
        bool wantHighlightCurrentButton;
        bool wantTabSwitchButton = true;
        int currentButton = 0;
        bool bChecked = false;
        //
        //LeftItems
        struct LeftItem
        {
            enum class Type : std::uint8_t
            {
                eText = 1 << 0,
                eButton = 1 << 1,
                eCheck = 1<<2
            };

            Type ItemType;
            std::wstring Caption;
        };
        std::list< LeftItem > leftItems; // 最多添加一个eCheck；

        PalletFooter();
        bool empty() const;

        const Color& backgroundColor() const;
        const Color& textColor() const;

        void setBackgroundColorCode(ColorCode code) { backgroundCode = code; }
        void setCaptionColorCode(ColorCode code) { captionCode = code; }

    private:
        ColorCode backgroundCode;
        ColorCode captionCode;
    };
    
    class QtPallet;
    class QtPalletHeader;
    namespace impl { class GNUF_IMPL_CLASS(Pallet); }
    class GNUF_BASE_EXPORT Pallet final : public gcmp::WeakReferenceable
    {
        GNUF_IMPL_USE(Pallet);
    public:
        explicit Pallet(ArrangementArea *, bool needHandle = false);
        explicit Pallet(bool resizable = false);
        ~Pallet();

        bool needHandle() const { return m_needHandle; }

        bool resizable() const { return m_resizable; }

        void refresh();

        void setCurrentQtButton(size_t buttonIndex);
        
        QWidget * qtWidget() const;
        QtPallet* qtPallet() { return m_qtPallet; };

        inline bool doesOperateArrangementArea() const { return (nullptr != m_operator.get()); }
        
        const ArrangementArea * area() const;
        ArrangementArea * area();

        bool visible() const;
        void show();
        void show(bool synchronously);
        void hide(bool completely);

        // 对话框是否被取消
        void setCanceled(bool canceled) { m_isCanceled = canceled; }
        bool isCanceled() { return m_isCanceled; }

        int x() const { return m_x; }
        int y() const { return m_y; }
        int width() const { return m_width; }
        int height() const { return m_height; }
        int minWidth() const { return m_minWidth; }
        int minHeight() const { return m_minHeight; }
        void setX(int x) { m_x = x; }
        void setY(int y) { m_y = y; }
        void setWidth(int width) { m_width = width; }
        void setHeight(int height) { m_height = height; }
        void setMinHeight(int height) { m_height = m_minHeight = height; }
        void setMinWidth(int width) { m_width = m_minWidth = width; }
        bool positionIsValid() const { return (m_x != 0 && m_y != 0); }
        bool sizeIsValid() const { return (m_width > 0 && m_height > 0); }
        void moveTo(int x, int y);
        void resize(int width, int height);
        
        inline const PalletHeader & header() const { return m_header; }
        inline const PalletFooter & footer() const { return m_footer; }
        inline PalletHeader & rHeader() { return m_header; }
        inline PalletFooter & rFooter() { return m_footer; }
        
        ///\brief Set the Qt content that will show in the pallet.
        ///\param qtContent: the pointer to the Qt content.
        ///\param owned: if true, the Qt content will be deleted, when the pallet is deleted.
        inline void setQtContent(QWidget * qtContent, bool owned = true);
        ///\return Return the Qt content.
        inline QWidget * qtContent() const;

        /// \brief Set the event handler through the client can get some events.
        void setEventHander(IPalletEventHandler * pEvtHandler) { m_wpEvtHandler = pEvtHandler; }
        /// \return Return the pointer to the event handler.
        IPalletEventHandler * eventHandler() { return m_wpEvtHandler.Get(); }
        /// \return Return the const pointer to the event handler.
        const IPalletEventHandler * eventHandler() const { return m_wpEvtHandler.Get(); }

        void setWantBorder(bool wantBorder) { m_wantBorder = wantBorder; }
        bool wantBorder() const { return m_wantBorder; }

        int headerHeight() const { return m_headerHeight; }

        void setPadding(int padding) { m_padding = padding; }
        int padding() const { return m_padding; }

        void setBackgroundColor(const Color& color) { m_backgroundColor = NEW_AS_OWNER_PTR(Color, color); }
        inline const Color* backgroundColor() const { return m_backgroundColor.get(); }

        void setScaleFactor(const ScaleFactor &);
        const ScaleFactor & scaleFactor() const { return m_scaleFactor; }

        void setRestrainedInWhatScenarios(std::uint8_t val) { m_restrainedInWhatScenarios = val; }
        std::uint8_t restrainedInWhatScenarios() const { return m_restrainedInWhatScenarios; }

        void setIsToolWindow(bool val) { m_isToolWindow = val; }
        bool isToolWindow() const { return m_isToolWindow; }

        void setWantToStayOnTop(bool val) { m_wantToStayOnTop = val; }
        bool wantToStayOnTop() const { return m_wantToStayOnTop; }

        /// \brief This is an internal interface.
        void onDestroyed(const QtPallet *);
    private:
        friend class QtPalletHeader;
        bool isDraggingAndMoving() const { return m_draggingAndMoving; }
        void setDraggingAndMoving(bool);
        void dragAndMove(const int, const int, const int, const int);
        void doubleClickOnHeader();
        void setHeaderHeight(int);
        gcmp::OwnerPtr< ArrangementAreaOperator > m_operator;
        const bool m_needHandle;
        const bool m_resizable;
        bool m_draggingAndMoving;
        QtPallet * m_qtPallet;
        PalletHeader m_header;
        PalletFooter m_footer;
        gcmp::WeakPtr< IPalletEventHandler > m_wpEvtHandler;
        bool m_wantBorder;
        int m_x, m_y, m_width, m_height, m_minWidth, m_minHeight;
        int m_headerHeight;
        int m_padding;
        gcmp::OwnerPtr<Color> m_backgroundColor;
        ScaleFactor m_scaleFactor;
        std::uint8_t m_restrainedInWhatScenarios;
        bool m_isCanceled;
        bool m_isToolWindow;
        bool m_wantToStayOnTop = false;
    };
}
